
#ifndef _TTG_PIPELINE_CONTEXT_MAP_
#define _TTG_PIPELINE_CONTEXT_MAP_
#include "Common/Definitions.h"

#include <vector>
#include "Common/Errors.h"
#include "Common/Math.h"
#include "Runtime.Low/Threads.h"

namespace ttg
{
	namespace pipeline
	{
		//Type, that defines unique context.
		typedef size_t ContextID;
	}
}

namespace ttg_internal
{
	namespace pipeline
	{
		//Class, that creates and releases IDs.
		//Note: it's thread safe!
		class ContextIDManager
		{
			private:
				ttg::pipeline::ContextID next_id;					//Unused ID for next context.
				std::vector<ttg::pipeline::ContextID> free_id;		//IDs, that was released.
				ttg::threads::FastCriticalSection locker;
			public:
				//Creates empty manager, that will provide unique IDs (for this manager only).
				inline ContextIDManager()
				{ next_id = 0; }
				//Returns new ID.
				inline ttg::pipeline::ContextID createContextID()
				{
					ttg::pipeline::ContextID res;
					locker.enter();
					if (free_id.size() != 0)
					{
						res = free_id[free_id.size() - 1];
						free_id.pop_back();
					}
					else
						res = next_id++;
					locker.leave();
					return res;
				}
				//Releases existent ID (and it can be reused).
				inline void releaseContextID(ttg::pipeline::ContextID ID)
				{
					locker.enter();
					free_id.push_back(ID);
					locker.leave();
				}
		};
	}
}

namespace ttg
{
	namespace pipeline
	{
		//Class, that provides context (that has T type) for each ContextID.
		//Note: it's thread safe!
		template <class T>
		class ContextMap
		{
			private:
				static const size_t BLOCK_SIZE = 1024;
				static const size_t BLOCK_COUNT = 16 * 1024;
				std::vector<std::vector<T> *> data;
				ttg::threads::AtomicInt max_block;				//number of the last block.
				ttg::threads::FastCriticalSection locker;		//locker for grid only (not for blocks).
			public:
				//Creates empty context map.
				inline ContextMap()
				{
					data.resize(BLOCK_COUNT, NULL);
					max_block.set(-1);
				}
				//Returns context, that corresponds to ID.
				inline T &operator[](ContextID ID)
				{
					//Getting block ID.
					size_t block_id = ID / BLOCK_SIZE;
#ifdef TTG_DEBUG
					if (block_id >= BLOCK_COUNT)
						throw Error(Error::FATAL, "ContextMap", "operator []",
									"Map is overflowed! Such recursion is evil!");
#endif
					//Resizing.
					if ((int)block_id > max_block.get())
					{
						locker.enter();
						for (size_t i = max_block.get() + 1; i < block_id + 1; i++)
						{
							data[i] = new std::vector<T>();
							data[i]->resize(BLOCK_SIZE);
						}
						max_block.set((int)block_id);
						locker.leave();
					}
					//Getting.
					return (*data[block_id])[ID % BLOCK_SIZE];
				}
				//Destroyes map.
				inline ~ContextMap()
				{
					locker.enter();
					SAFE_DELETE_CONTENT(&data);
					locker.leave();
				}
		};
	}
}

#endif
